package modules.pathloss;

import com.vividsolutions.jts.geom.Geometry;

import javax.naming.directory.InvalidAttributesException;

import datatypes.Antenna;
import modules.pathloss.model.CostHata;
import modules.pathloss.model.Erceg;
import modules.pathloss.model.FreeSpace;
import modules.pathloss.model.WI_LOS;
import tools.settings.Settings;
import tools.settings.SettingsMissingException;

/**
 * <p>The MAPL implementation for omnidirectional antennas. </p>
 *
 * @author Lynne Vandousselaere
 */
class NewOdMAPL implements MAPL {
    // the linkbudget calculator

    LinkBudgetCalculator linkbudget = new LinkBudgetCalculator();

    // the pathloss adapter for calculating pathloss stuff
    PathLossAdapter pathloss = PathLossAdapter.getInstance();
    private final int sides = 32;
    private String[] nsettings = {"plm"};

    /**
     * <p>Constructs a new MAPL for omnidirectional antennas.</p>
     */
    public NewOdMAPL() {
    }

    @Override
    public Geometry getCoverage(Antenna a, Settings settings)
            throws SettingsMissingException {
        double radius = getRadius(a, settings, 1);

        return tools.gis.GisTools.createCircleInLambertFormat(a.getX(), a.getY(), radius, sides);
    }

    @Override
    public double getRangeRadius(Antenna a, Settings settings)
            throws SettingsMissingException {
        String[] snames = {"rangeFactor"};
        if (!settings.contains(snames))
            throw SettingsMissingException.generate("OdMAPL", "getRangeRadius", snames);

        int rangeFactor = Integer.parseInt(settings.getSettingsValue("rangeFactor"));
        return getRadius(a, settings, rangeFactor);
    }

    /** **********************************************
     *  Private methods
     *  **********************************************/
    /**
     * <p>Calculates the radius of an antenna where there is maximum allowable
     * path loss from the given antenna, settings and rangefactor.</p>
     *
     * @param a
     * @param settings
     * @param rangefactor
     * @return
     * @throws javax.naming.directory.InvalidAttributesException
     */
    private double getRadius(Antenna a, Settings settings, int rangefactor)
            throws SettingsMissingException {

        double sectors_dl = 0;
        double sectors_ul = 0;
        double surf_dl = 0;
        double surf_ul = 0;
        double sectors = 3;
        double sectors_req;
        double capac_dl = 400;
        double capac_ul = 80;
        double v_simusage = 0.05;

        double surface;

        int mod = 0;
        double radius_dl = 0;
        double radius_ul = 0;

        while(settings.getSettingsValue("rcv_sens_dl_".concat(Integer.toString(mod))) != null){
            if(sectors_dl != sectors){
                double downlink = linkbudget.getPathLossComponent(settings, a, true, mod);
                double[] pl_log_d = getLogDistance(a, settings);

                // convert back. log10 distance (m) = (linkbudget - a)/b *1000
                // or distance (m) = 10^((lb-a)/b) *1000
                radius_dl = Math.pow(10, (downlink - pl_log_d[0]) / pl_log_d[1]) * 1000*0.1;

                surface = 3*Math.pow(radius_dl/1000,2)*Math.sin(Math.PI/3)-surf_dl;

                sectors_req = surface * capac_dl * v_simusage /Double.parseDouble(settings.getSettingsValue("bitrate_dl_".concat(Integer.toString(mod))));
                    if(sectors_dl + sectors_req > sectors){
                        surf_dl = surf_dl + (sectors - sectors_dl) * Double.parseDouble(settings.getSettingsValue("bitrate_dl_".concat(Integer.toString(mod)))) / (capac_dl * v_simusage);
                        sectors_dl = sectors;
                    } else{
                        surf_dl = surf_dl + surface;
                        sectors_dl = sectors_dl + sectors_req;
                    }
            }
            if(sectors_ul != sectors){
                double uplink = linkbudget.getPathLossComponent(settings, a, false, mod);
                double[] pl_log_d = getLogDistance(a, settings);

                // convert back. log10 distance (m) = (linkbudget - a)/b *1000
                // or distance (m) = 10^((lb-a)/b) *1000
                
                radius_ul = Math.pow(10, (uplink - pl_log_d[0]) / pl_log_d[1]) * 1000;

                surface = 3*Math.pow(radius_ul/1000,2)*Math.sin(Math.PI/3)-surf_ul;

                sectors_req = surface * capac_dl * v_simusage /Double.parseDouble(settings.getSettingsValue("bitrate_ul_".concat(Integer.toString(mod))));
                    if(sectors_ul + sectors_req > sectors){
                        surf_ul = surf_ul + (sectors - sectors_dl) * Double.parseDouble(settings.getSettingsValue("bitrate_ul_".concat(Integer.toString(mod)))) / (capac_ul * v_simusage);
                        sectors_ul = sectors;
                    } else{
                        surf_ul = surf_ul + surface;
                        sectors_ul = sectors_ul + sectors_req;
                    }


            }
            mod++;

        }
        //System.out.println(Math.min(radius_dl,radius_ul));
        return (Math.min(radius_dl, radius_ul) * rangefactor);
    }

    private double[] getLogDistance(Antenna a, Settings settings)
            throws SettingsMissingException {
        String plm_par = settings.getSettingsValue("PLM");

        if (plm_par == null)
            throw SettingsMissingException.generate("NewOdMAPL", "getLogDistance", nsettings);
        else {
            if (plm_par.equalsIgnoreCase("costhata"))
                return new CostHata().getLogDistance(settings, a);
            if (plm_par.equalsIgnoreCase("freespace"))
                return new FreeSpace().getLogDistance(settings, a);
            if (plm_par.equalsIgnoreCase("wilos"))
                return new WI_LOS().getLogDistance(settings, a);
            if (plm_par.equalsIgnoreCase("erceg"))
                return new Erceg().getLogDistance(settings, a);
        }

        // faulty name of plm.
        throw new IllegalArgumentException("NewOdMAPL - (getLogDistance) " +
                "argument PLM is incorrect (" + plm_par + "), allowed are: COSTHATA, FREESPACE, WILOS, ERCEG");
    }
}
